package Bio::Rambam::Proteomics::Structures::MzMLSpectrum;

use Moose;
use namespace::autoclean;
extends 'Bio::Rambam::Proteomics::Structures::Spectrum';
use Bio::Rambam::Proteomics qw($FRAGMENTATIONS);

use Moose::Util::TypeConstraints;
use MIME::Base64;
use XML::LibXML;
use Try::Tiny;
use Data::Dumper;
use XML::LibXML;
use XML::LibXML::XPathContext;


# cv_params_related terms
enum 'spectrum_types', [qw(MS1 MSn)];						#children of MS:1000524: there are lots of them!!! Only MS1 and MSn terms (MS:1000579 and MS:1000580 resp.) will be considered
enum 'scan_polarities',[qw(negative positive)];				# negative (MS:1000129) or positive (MS:1000130), both children to "scan polarity" (MS:1000465)
enum 'representations',[qw(centroid profile)];				# centroid spectrum (MS:1000127) or profile spectrum (MS:1000128), both children to "spectrum representation" (MS:1000525)
has 'type'			=>	(is=>'rw',isa=>'spectrum_types');	# see enum spectrum_types
has 'scan_polarity'	=>	(is=>'rw',isa=>'scan_polarities');	# see enum scan_polarities
has 'representation'=>	(is=>'rw',isa=>'representations');	# see enum representations

#### Building from text
has 'text_mzML'				=>	(is=>'rw',isa=>'Str',trigger =>\&_populate_mzML,clearer => 'clear_text_mzML');
has 'base_peak_mz'			=>	(is=>'rw',isa=>'Num'); 	#value of MS:1000504 -> The mz of the most intense peak in the mass spectrum.
has 'base_peak_int'			=>	(is=>'rw',isa=>'Num'); 	#value of MS:1000505 -> The intensity of most intense peak in the mass spectrum.
has 'lowest_mz'				=>	(is=>'rw',isa=>'Num'); 	#value of MS:1000528 -> The lowest observed mz in the mass spectrum.
has 'highest_mz'			=>	(is=>'rw',isa=>'Num'); 	#value of MS:1000527 -> The highest observed mz in the mass spectrum.
has 'total_ion_current'		=>	(is=>'rw',isa=>'Num'); 	#value of MS:1000285 -> Total ion current




sub clear_binary_data{
	my ($self)=shift;
	$self->clear_mzArrayBinary_precission;
	$self->clear_mz_ArrayBinary_endian;
	$self->clear_mz_ArrayBinary_array;
	$self->clear_int_ArrayBinary_precission;
	$self->clear_int_ArrayBinary_endian;
	$self->clear_int_ArrayBinary_array;
}

sub clear_spectrum_data{
	my ($self)=shift;
	$self->clear_binary_data();
	$self->clear_array_int_translated;
	$self->clear_array_mz_translated;
}


sub _populate_mzML{
	my ( $self, $mzML_text, $old_mzML_text ) = @_;
	my $parser = XML::LibXML->new();
	my $doc;
	return unless $mzML_text;
	$doc = $parser->parse_string($mzML_text);	
	foreach my $spectrum ($doc->findnodes('spectrum')) {
		my $index=$spectrum->findvalue('@index');
		my $id=$spectrum->findvalue('@id');
		my $defaultArrayLength=$spectrum->findvalue('@defaultArrayLength');
		$self->index($index);
		$self->id($id);
		$self->defaultArrayLength($defaultArrayLength);
		foreach my $cv ($spectrum->findnodes('cvParam')) {
			my $cv_id=	$cv->findvalue('@accession');
			my $cv_value=$cv->findvalue('@value');
			$self->ms_level		($cv_value) if $cv_id eq 'MS:1000511';
			$self->base_peak_mz	($cv_value) if $cv_id eq 'MS:1000504';
			$self->base_peak_int($cv_value) if $cv_id eq 'MS:1000505';
			$self->lowest_mz($cv_value) if $cv_id eq 'MS:1000528';
			$self->highest_mz($cv_value) if $cv_id eq 'MS:1000527';
			$self->total_ion_current($cv_value) if $cv_id eq 'MS:1000285';
			#print $cv_id,"\n";
		}
		my $scan_count=	$spectrum->findvalue('/scanList/@count');
		foreach my $cv ($spectrum->findnodes('/scanList/cvParam')) {
			my $cv_id=	$cv->findvalue('@accession');
			my $cv_value=$cv->findvalue('@value');
			$self->scan_combination_tipes('mean of spectra') if $cv_id eq 'MS:1000575';
			$self->scan_combination_tipes('median of spectra') if $cv_id eq 'MS:1000573';
			$self->scan_combination_tipes('sum of spectra') if $cv_id eq 'MS:1000571';
			$self->scan_combination_tipes('no combination') if $cv_id eq 'MS:1000795';
		}

		#############################################################################return if $self->ms_level ==1;
		foreach my $precursor ($spectrum->findnodes('precursorList/precursor')) {
			foreach my $cv($precursor->findnodes('activation/cvParam')){
				my $cv_id=	$cv->findvalue('@accession');
				my $cv_value=$cv->findvalue('@value');
				my %fragmentations=reverse %{$FRAGMENTATIONS};
				$self->fragmentation($fragmentations{$cv_id}) if defined $fragmentations{$cv_id};
				
			}
			
			foreach my $selectedion($precursor->findnodes('selectedIonList/selectedIon')){
				foreach my $cv($selectedion->findnodes('cvParam')){
					my $cv_id=	$cv->findvalue('@accession');
					my $cv_value=$cv->findvalue('@value');
					$self->precursor_mz($cv_value) if $cv_id eq 'MS:1000744';
					$self->precursor_z($cv_value) if $cv_id eq 'MS:1000041';
					$self->precursor_int($cv_value) if $cv_id eq 'MS:1000042';
				}
			}
		}
		
		foreach my $array ($spectrum->findnodes('binaryDataArrayList/binaryDataArray')) {
				my $compression;
				my $bits;
				my $type;
				my $array_string=	$array->findvalue('binary');				
				foreach my $cv ($array->findnodes('cvParam')) {
					$bits=64 if $cv->findvalue('@accession') eq 'MS:1000523';
					$bits=32 if $cv->findvalue('@accession') eq 'MS:1000521';
					
					$compression='no_compression' if $cv->findvalue('@accession') eq 'MS:1000576';
					$compression='zlib_compression' if $cv->findvalue('@accession') eq 'MS:1000574';
					
					$type= 'mz_array'  if $cv->findvalue('@accession') eq 'MS:1000514';
					$type= 'int_array'  if $cv->findvalue('@accession') eq 'MS:1000515';
				}
				if($type eq 'mz_array'){
					$self->mz_ArrayBinary_precission($bits);
					$self->mz_ArrayBinary_compression($compression);
					$self->mz_ArrayBinary_array($array_string);	
				}
				elsif($type eq 'int_array'){
					$self->int_ArrayBinary_precission($bits);
					$self->int_ArrayBinary_compression($compression);
					$self->int_ArrayBinary_array($array_string);
				}
		}
		$self->clear_text_mzML;	#The XML text is cleared
	}
}




#defaultArrayLength="163"
#Compr:
	#mz -> 
    #eJwl0FlIVGEYxvGPEopWK6Iygsi6qBspMRUtPqFIChdwwQxqRs2msdxmRkcz+3JJHUOYgjLXJIkwcq2LLO2MtFEJVkpOkIlZZtZkOhVlSPg8Vz/+7/ueM4cRQmiL9QlSCCF/GxNh65ukOTW/H1DNrDPMKfxDoLxzCCrbteO4e7jHiHl4IrUXQBVfDUW8IwV3hiFa8u8E9hX3T2Lv+5qm9qRCxyCUhuE0mPwLiiP56XhuoR1qX+toejvnri76pI/uqsjAvv4q9WylNwIy8b7Ph6HmlQfll70mdG8EFDF69rcU9vrNZjgeQp/paEAGlIMKqtw6doSPBd2og3LpOyiaJzl3iSy41gSFu5jdX8N2lGbjuTUNUNvSCkXlEFTtbu7d9VZoboFiRZeV//dT9rzbOdgHd0PNo59tceXw931y4ZVAKKPCqZceat6ZbJuitd28f9ALRYv3KdztTIZiSSb1U1D6noeqtIFmzXAeuCkPXbQdipUZUGtycl4TdBp3ydFQxB5jv7eyw2rZpmaobr5gf3KzHT756EvB1BQKVWwRu+UiW12H4mMn59mPOLeMcq7+0LseZ/B9Y6vodAVUB+ugsIcqfqeOBvVBZXTS6N1n8dyCSCh62thpnWzLSyjN8QXotwl0mRFqBdPsiRka4lkIcy9D9fwe1fkX4T4gjHZEQbXfCcUG72LMv8dBmV7J3tcBlf4VfTzCvXmC+6Yp2rb1HN6zegfUTEFQuhRUVhv1u8B58KIS3MccgNpAJHt5IVRHnewPI+yecfasVym6bCOd3QblcBJ7zE4NE5zfmqLhfzlvriqDAw1Qzh+F4me1Dd9RNQnlQF457uIKoci3l8v/R/ZcoQ==
    #int->
    #eJwlkktIlGEUhh/tQprEBDaYSgwRYVZk5UJKcpQ55xspZCCDoqCpXLQwkCFoaJF/Ypu0UEsaTErSQszINmFhNUSgqZRBxNgF7YKrChdGQS462vL/fs57ec4hdlHpfS4EZkL4tgmpO0JjujIwqQS3CvpF6Xit7DmvdCWE+d1KZ5pSt128vt8OvDLipY7pUiE4rvYdJG56Hz2l4pS9o3ifQvz5JqxOOHY0KPP7lJaQ0JOr1OQoo2OavHEgTH/KfJcKkWFh5LPg/6DMTCmJPqHW/ffPttkXG5TC9eb9Q/hZ4fDVKxPmPzgtzOYJTy8o0YfC2dtKU61jxVubbRUOXhNizcrpoOWsFnqtqy+gix0iv4TuTMtw2Hqr+WqYVJswt1kpPmb614W2NMdEhhB9JdQ9Fp5FHNlrlcz3ypD9u7pECZUoPcPW2XgFTLPfp0TiQtVNDU72h+n4rgzOanJVXpjGeaWxXb3CNutCOTXVNnNCyL9r863ivexwJHOE/bmO6DJjtdKRMr0hvyNUrJSuUZqXK3OHjKG/kqlRR+cVpcE4Vo0ZJ7/pWd6JmPE4Yns9bt3KhHCBkpWlXL6vTO8UWtKFgZPCpgdhL/eJI2eLUlQvxP8KiXfCrm7Ls/B2VCiy3Ra1C94ChwKhfK9lazCWliu90rGuRSm5ZexHFu/He/PVca/LET9nO6iwvGeUZJP5bbRc43Zfj+yWLin5GfoPh/HGag==

#No compression
	#mz ->
	#AAAAwAthYkAAAABA92pjQAAAAECw12RAAAAAwDXxZEAAAACA+xloQAAAAAA3QWhAAAAAQLVbaEAAAACAiqNpQAAAAMDERGpAAAAAQE5jakAAAABAkYJqQAAAAIBam2pAAAAAAFrBa0AAAADAaN5rQAAAAMCH/GxAAAAAgI68bUAAAAAAM9NtQAAAAABuwm5AAAAAAMHYbkAAAABAaOBvQAAAAEBm9m9AAAAAAF9+cEAAAACACJFwQAAAAMDsnnBAAAAAwHCycEAAAACA7r1wQAAAAIDH0HBAAAAAgD2OcUAAAADAn6BxQAAAAMAQsHFAAAAAwKg4ckAAAAAA6F5yQAAAAMAafHJAAAAAQOpFc0AAAADAzU9zQAAAAABVYXNAAAAAwO1rc0AAAAAAGyR0QAAAAADpQXRAAAAAAMpgdEAAAAAAOHF0QAAAAEDYgHRAAAAAgHqedEAAAABATy91QAAAAICkYHVAAAAAQA3ddUAAAAAArvB1QAAAAIDuAHZAAAAAgBhzdkAAAAAA9IV2QAAAAIDUnHZAAAAAAMGId0AAAABAF6F3QAAAAMAlsHdAAAAAAJjed0AAAACAsvR3QAAAAED0n3hAAAAAQHSveEAAAAAAEb14QAAAAMBoyHhAAAAAAAK0eUAAAABAPL55QAAAAMAE1HlAAAAAQHXueUAAAACAGC96QAAAAICZOXpAAAAAQFNOekAAAABAGmF6QAAAAMAjcnpAAAAAQIqAekAAAABAnb56QAAAAIC/zXpAAAAAAK8je0AAAADANmZ7QAAAAAAMcntAAAAAADWAe0AAAABAM4x7QAAAAICIoXtAAAAAgHb7e0AAAABAOSJ8QAAAAICEMXxAAAAAABJxfEAAAADAqtl8QAAAAICcO31AAAAAQGZUfUAAAAAAVmd9QAAAAEDfeH1AAAAAAE2dfUAAAABAc659QAAAAICrzH1AAAAAQOb0fUAAAACAwS9+QAAAAECWPH5AAAAAQHNIfkAAAACAVoR+QAAAAECvk35AAAAAgICmfkAAAAAA5bp+QAAAAEB3xX5AAAAAgHXkfkAAAAAAgPl+QAAAAAC5BH9AAAAAwOcTf0AAAADA845/QAAAAIBZnn9AAAAAAJFIgEAAAAAAVmCAQAAAAAA70IBAAAAAgGrZgEAAAACAVD6BQAAAAMAHUIFAAAAAAMKxgUAAAADAb7qBQAAAAAB10YFAAAAAQHRagkAAAAAA2mKCQAAAAAAOaoJAAAAAwILzgkAAAAAA6/uCQAAAAABBEINAAAAAAHqXg0AAAACAy7uDQAAAAIBgN4RAAAAAwDhNhEAAAADAs1OEQAAAAIBK2YRAAAAAAB0jhUAAAADA71iFQAAAAEBwmIVAAAAAwEezhUAAAACAYdKFQAAAAIDG4oVAAAAAQHTrhUAAAADAqvKFQAAAAMCxKYZAAAAAABUyhkAAAADAczuGQAAAAEDugIZAAAAAgHiKhkAAAACANZKGQAAAAEA8CodAAAAAAFVLh0AAAADA1VCHQAAAAAAPg4dAAAAAgGXZh0AAAAAA4+KHQAAAAIDC6YdAAAAAAP4aiEAAAACAiSCIQAAAAID+KohAAAAAQOBkiEAAAACA55GIQAAAAIBo64hAAAAAQK3yiEAAAABATvqIQAAAAICumolAAAAAgNWhiUAAAABAA+SJQAAAAAD1m4pAAAAAwJrwikAAAABA1XyLQAAAAIBYg4tAAAAAAH6Ri0A=
    #int->
    #AHKKRgCowkUAIOZEABAvRQDYpkUAhAJGALDZRgBALUUARuJGAJrPRgA+gUYAoJhFAPw7RgCcAUYAcDFFgKr3RwAAgD8AeDxHAOA8RQBAzEYAAIBAAHjCRQDcgEYAQm1HAOAARgCA3UQA+ORFABGYRwAygkYA/ExGAJBERQCkGkYAZBhGAMrLRsCeVUgArNhGALAERQBQx0UAyOFFABbbRgDm30YAmKpFAGxHRgCgmEUAFExGAMQkRgAqIkcAAO1FAO5CRwAQf0YA0DxFALjgRQDwG0UAvoVGAGC2RQB6pUYAi2xHAAjURgCgkUUAWJdFAHKMRgB0QEYAAFRFAKimRQAQIEYAAIA/AFD1RQCjCkgArFtGAEBGRgDmRkgA2JJFAPQrRgA0YUYA0JtFAJIBRwDQCUUAYM5FAHC6RQC/UEcAFBlGAAraRgC8AUcAlANGAEQ4RgCkx0YAgIFGACD1RQCsEEYAUHhFAE6fRkDZrEgAmuxGALjwRsAOG0gAhPxGAISVRoAqkkcAAABBAGRURgAgY0UAHKtGAICRRYDJmkcAwBhFAFMaRwBgBUYAZAtHANgQRgC8FkcARDRGADwVRgCMBkYA9FlGAMoWSQDfykcAnJNGAILYRgBOy0YAxBZGACAJRQDQckYAYFxFAIRiRgBAP0UASChGAAwMRgCOr0YA4DNFAJACRQCwaEUAKbFIgBq9RwAYLEYAMH9FAHj7RQCY1kUAOqNGAIAsRgAwX0UAMMJFADCVRQCACUUAYChFAEFLRwBggkUAqBBGAAJJRwAekEYAOKJFAHrIRgBALUWA0eNHAK2gRwB4fkYAoEJGAIx3RgDAi0UAsCZFANDMRQBGuUYAcI1GABwJRg==


__PACKAGE__->meta->make_immutable;



